package lp2.projeto.agenda;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import lp2.projeto.database.Database;
import lp2.projeto.gerenciador.*;
import lp2.projeto.horario.*;
/**
 * Classe responsavel pela interface e interacao com o usuario.
 *
 */
public class Agenda {
	private static Perfil perfil;
	private static Scanner teclado = new Scanner(System.in);
	private static Gerenciador gerente = new Gerenciador();
	private static final String FORMATO_INVALIDO = "Formato Invalido, por favor repita o que lhe foi pedido";     
	private static final String DATA_EVENTO = "Em que data ocorrera o evento (DD/MM/AAAA): ";
	private static final String DATA_CONTATO = "Qual a data de aniversario do contato (DD/MM/AAAA): ";
	private static final String NOVA_DATA_CONTATO = "Qual a nova data de aniversario do contato (DD/MM/AAAA): ";
	private static final String[] opcoesAtualizaPerfil = {
		"1 - Alterar nome do Perfil",
		"2 - Alterar email do Perfil",
		"3 - Alterar descricao do Perfil\n",
		"0 - Voltar\n"
	};
	private static final String[] opcoesAtualizaFormaDeContato = {
		"1 - Alterar o tipo da Forma de Contato",
		"2 - Alterar o endereco da Forma de Contato",
		"3 - Alterar o comentario da Forma de Contato\n",
		"0 - Voltar\n"
	};
	private final static String[] opcoes = {
			"1 - Adicionar Evento" , 
			"2 - Adicionar Contato", 
			"3 - Adicionar Contato ao evento",
			"4 - Atualizar Contato",
			"5 - Remover Contato",
			"6 - Atualizar seu Perfil",
			"7 - Listar todos os contatos",
			"8 - Listar todos os eventos",
			"9 - Listar os eventos de um certo contato",
			"0 - Sair da Agenda\n"
		};
	private final static String[] opcoesAtualizaContato = {
			"\n\n1 - Alterar o nome do contato",
			"2 - Alterar o endereco do contato",
			"3 - Alterar a data de aniversario do contato",
			"4 - Alterar uma forma de contato do contato",
			"5 - Adicionar uma forma de contato do contato",
			"6 - Remover uma forma de contato do contato\n",
			"0 - Voltar\n"
		};
	
	private final static String[] opcoesAddEventoConflito = {
		"\nHa um conflito de horarios",
		"1 - Sobrecarregar o hor�rio",
		"2 - Desistir do novo evento",
		"3 - Descartar eventos conflitantes"
	};
	
	
	
	 //Main         ----------------------------------------------------------------
	 
	/**
	 * Main, metodo principal responsavel pelo come�o do programa chamando o metodo de menu principal
	 */
	public static void main(String[] args) {
		try {
			perfil = (Perfil) Database.lerObjeto("DatabasePerfil");
			if (!(perfil instanceof Perfil)) throw new Exception("Perfil null");
			gerente =  (Gerenciador) Database.lerObjeto("DatabaseGerente");
			if (!(gerente instanceof Gerenciador)) throw new Exception("Gerenciador null");
		} catch (Exception e) {
			System.out.println(e);
			String nome,email,descricao;
			System.out.println("Bem vindo a Agenda Multitudo\n");
			System.out.println("Como eh a sua primeira visita nos forneca alguns dados sobre voce\n");
			System.out.print("Digite seu nome: ");
			nome = teclado.nextLine();
			System.out.print("Digite seu email: ");
			email = teclado.nextLine();
			System.out.print("Uma pequena descricao sobre voce: ");
			descricao = teclado.nextLine();
			perfil = new Perfil(nome, email, descricao);
		}
		
		do{
			menuPrincipal();
		}while (opcaoMenuPrincipal(escolha(0,9)) != 0);
	
	
	}
	
	 //Metodos Menu       ----------------------------------------------------------------
	
	/**
	 * Metodo que imprime na tela o Menu Principal com todas suas opcoes
	 */
	private static void menuPrincipal(){
		System.out.println("\n- Agenda Multitudo - \n");
		for (String opcao : opcoes){
			System.out.println(opcao);
		}
	}
	/**
	 * Metodo que recebe uma escolha numerica do usuario, o numero tem que estar dentro de um limite
	 * @param primeira Limite inferior da escolha
	 * @param ultima Limite superior da escolha
	 * @return int - Escolha do usuario
	 */
	private static int escolha(int primeira, int ultima) {
		int retorno;
		System.out.print("Digite sua escolha: ");
		do {
			try {
				retorno = Integer.parseInt(teclado.nextLine());
				break;
			} catch (Exception e) {
				System.out.println("Opcao Invalida");
				retorno = escolha(primeira,ultima);
				break;
			}
		} while (true);	
		if (retorno >= primeira && retorno <= ultima) {
			return retorno;
		}
		System.out.println("Opcao Invalida");
		return escolha(primeira,ultima);	
	}
	/**
	 * Metodo que ao receber a escolha do usuario chama o metodo correspondente
	 * @param escolha Escolha do usuario
	 * @return Escolha do usuario
	 */
	private static int opcaoMenuPrincipal(int escolha){
		switch(escolha){
		case(1):
			leituraAdicionaEvento();
			break;
		case(2):
			leituraCadastraContato();
			break;
		case(3):
			leituraAdicionaContatoAoEvento(leituraBuscaEvento());
			break;
		case(4):
			leituraAtualizaContatos();
			break;
		case(5):
			leituraRemoverContato();
			break;
		case(6):
			leituraAtualizaPerfil();
			break;
		case(7):
			listarContatos();
			break;
		case(8):
			listarEventos();
			break;
		case(9):
			listarEventosDoContato();
			break;
		case(0):
			try {
				Database.salvarObjeto("DatabasePerfil", perfil);
				Database.salvarObjeto("DatabaseGerente", gerente);
			} catch (IOException e) {
				System.out.println(e);
			}
		}
		return escolha;
		
	}
	
	
	
	
	  //  Metodos Principais ----------------------------------------------------------------
	/**
	 * Lista os eventos e seus respectivos contatos
	 * @param lista Lista dos eventos
	 */
	private static void listarEventos(List<Evento> lista) {
		 for(Evento e : lista) {
			 System.out.println(e);
			 System.out.println("Contatos participantes:");
			 for(Contato c : gerente.getContatoPorEvento(e))
				 System.out.println("\t" + c.getNome());
			 System.out.println();
		 }
		 if (lista.size() == 0)
			 System.out.println("(Nenhum evento)\n");
	 }
	/**
	 * Lista os eventos futuros e passados do gerenciador
	 */
	private static void listarEventos() {
		 Horario horaAtual = Horario.getHoraAtual();
		 List<Evento> listaPassado = new ArrayList<Evento>();
		 List<Evento> listaFuturo = new ArrayList<Evento>();
		 
		 for (Evento evento : gerente.getEventos()) {
			 if (evento.getIntervalo().compareTo(horaAtual) <= 0)
				 listaPassado.add(evento);
		 }
		 for (Evento evento : gerente.getEventos())
			 if (evento.getIntervalo().compareTo(horaAtual) > 0)
				 listaFuturo.add(evento);
		 
		 System.out.println("Eventos passados:\n");
		 listarEventos(listaPassado);
		 System.out.println("Eventos futuros:\n");
		 listarEventos(listaFuturo);
	 }
	 /**
	  * Lista os eventos do contato.
	  * @param contato Contato do qual os eventos serao listados
	  */
	private static void listarEventosDoContato(Contato contato) {
		System.out.println("\nEventos de " + contato.getNome() + ":\n");
		listarEventos(gerente.getEventoPorContato(contato));
	}
	/**
	 * Lista os eventos do contato que vai ser buscado.
	 */
	private static void listarEventosDoContato() {
		Contato contato = leituraBuscaContatoPorNome();
		if (contato != null)
			listarEventosDoContato(contato);
	}	
	/**
	 * Lista os contatos do gerenciador.
	 */
	private static void listarContatos() {
		 for(Contato c : gerente.getContatos()) {
			 System.out.println(c + "Eventos participantes:");
			 for(Evento e : gerente.getEventoPorContato(c))
				 System.out.println("\t" + e.getNome());
			 System.out.println((gerente.getEventoPorContato(c).isEmpty() ? "nao participa de nenhum evento" : "") + "\n");
		 }
	 }
	
	private static boolean leituraSimNao(String msg) {		
		System.out.print(msg);
		String resposta = teclado.nextLine().toLowerCase();
		
		return !resposta.equals("s") && !resposta.equals("sim") && !resposta.equals("n") && !resposta.equals("nao") ?
				leituraSimNao("Resposta invalida, digite novamente: ") :
					(resposta.equals("s") || resposta.equals("sim"));
	}
	
	 /**
	 * Oferece uma lista de contatos, da qual o usuario escolhe qual sera removido.
	 */
	private static void leituraRemoverContato(){
		System.out.println("- Excluir contato -\n");
		Contato contato = leituraBuscaContatoPorNome();
		if (!(contato instanceof Contato)) return;
		
		String msg = "Realmente deseja excluir o contato " + contato.getNome() + ": (sim,s/nao,n)";
		
		if (leituraSimNao(msg)) gerente.removeContato(contato);
		else {
			msg = "Deseja remover um contato diferente: (sim,s/nao,n)";
			if (leituraSimNao(msg)) leituraRemoverContato();
		}
		
	}
	/**
	 * Recebe os dados do usario para cadastro de um novo contato.
	 */
	private static void leituraCadastraContato(){
		String nome,endereco,dataNiver;
		
		System.out.print("Qual nome do contato: ");
		nome = teclado.nextLine();
		
		System.out.print("Qual o endereco do contato: ");
		endereco = teclado.nextLine();
		
		dataNiver = leituraData(DATA_CONTATO);
		
		ArrayList<FormaDeContato> formasDeContato = new ArrayList<FormaDeContato>();
		
		String msg = "Deseja adicionar outra forma de contato? (sim,s/nao,n)";
		do {
			formasDeContato.add(leituraFormaDeContato());
		} while (leituraSimNao(msg));
		
		gerente.adicionaContato(new Contato(nome, endereco, dataNiver, formasDeContato));							
	}
	/**
	 * Recebe os dados do usario para cadastro de um novo evento.
	 * Tambem oferece a funcao de adicionar um contato ao evento recentemente criado.
	 */
	private static void leituraAdicionaEvento(){
		String nome, data, descricao,tipo;
		int duracao;
		Horario horario;
		
		System.out.print("Qual o nome do evento: ");
		nome = teclado.nextLine();
		
		data = leituraData(DATA_EVENTO);
		
		horario = leituraHorario(data);
		
		System.out.print("De uma descricao para o evento: ");
		descricao = teclado.nextLine();
		
		duracao = leituraDuracao();
		
		String msg = "Deseja catalogar o evento em algum tipo: (sim,s/nao,n)";
		
		if (leituraSimNao(msg)){
			System.out.print("Qual o tipo: ");
			tipo = teclado.nextLine();
		} else {
			tipo = "Nao catalogado ainda";
		}
		Evento e = new Evento(nome,horario,descricao,duracao, tipo);
		if(checaConflitoDeEventos(e)) return;
		
		msg = "Deseja adiciona um contato ao evento: (sim,s/nao,n)";
		
		if (leituraSimNao(msg)){
			do {
				leituraAdicionaContatoAoEvento(e);
				msg = "Deseja adicionar outro contato ao evento? (sim,s/nao,n)";
			} while (leituraSimNao(msg));
		}
	}
	
	/**
	 * Faz a checagem de conflito de horario entre os eventos registrados e o novo evento
	 * @param event novo evento
	 * @return se o novo evento nao deve ser adicionado
	 */
	private static boolean checaConflitoDeEventos(Evento event) {
		for(Evento e : gerente.getEventos())
			if(e.getIntervalo().colideCom(event.getIntervalo()))
				return resolveConflitoDeEventos(event);
		return false;
	}
	
	/**
	 * Resolve conflito de horario entre eventos caso haja um
	 * @param event novo evento
	 * @return se o novo evento nao deve ser adicionado
	 */
	private static boolean resolveConflitoDeEventos(Evento event) {
		for(String str : opcoesAddEventoConflito)
			System.out.println(str);
		
		switch (escolha(1, opcoesAddEventoConflito.length)) {
		case(1):
			gerente.adicionaEvento(event);
			return false;
		case(3):
			for (Evento evento : gerente.getEventos())
				if(evento.getIntervalo().colideCom(event.getIntervalo()))
					gerente.removeEvento(evento);
		
			gerente.adicionaEvento(event);
			return false;
		}
		return true;
	}
	
	
	/**
	 * Oferece uma lista ou busca do contato que sera adicionado ao evento.
	 * @param e Evento o qual sera adicionado um contato
	 */
	private static void leituraAdicionaContatoAoEvento(Evento e) {
		if (!(e instanceof Evento)) return;
		
		System.out.println("\n\n" + e + "\n");
		Contato contato = leituraBuscaContatoPorNome();
		
		if (contato == null)
			return;
		
		String msg = "Adicionar Contato " + contato.getNome() + " ao evento " +  e.getNome() + ", deseja proceder: (sim,s/nao,n)";
		
		if (leituraSimNao(msg)){
			gerente.adicionaContatoAEvento(contato, e);
		} else {
			msg = "Deseja adicionar um contato diferente: (sim,s/nao,n)";
			
			if (leituraSimNao(msg))
				leituraAdicionaContatoAoEvento(e);
		}
		
		
	}
	/**
	 * Oferece uma lista ou busca do contato ao qual se deseja modificar ou adicionar dados.
	 */
	private static void leituraAtualizaContatos(){

		System.out.println("\n");
		System.out.println("1 - Ver uma listagem de todos os contatos");
		System.out.println("2 - Buscar contato utilizando uma parte do nome");
		System.out.println("0 - Para voltar");
		int escolha = escolha(0,2);
		switch (escolha){
		case(1):
			int i = 1;
			System.out.println("\n");
			for(Contato contato : gerente.getContatos()){
				System.out.println(i++ + " - " + contato.getNome());
			}
			int escolhaSecundaria = escolha(0 , gerente.getContatos().size());
			if (escolhaSecundaria == 0){
				leituraAtualizaContatos();
				break;
			} else {
				leituraAtualizaContatos(gerente.getContatos().get(escolhaSecundaria - 1));
			}
			break;
		case(2):
			leituraAtualizaContatos(leituraBuscaContatoPorNome());
			
		}	
	}
	/**
	 * Mostra as opcoes de modificacao e atualizacao de dados do contato.
	 * @param c Contato que esta sendo atualizado
	 */
	private static void leituraAtualizaContatos(Contato c){
		if (!(c instanceof Contato)) return;
		System.out.println("\n\nModificando o contato " + c.getNome() + "\n");
		for (String opcoes : opcoesAtualizaContato){
			System.out.println(opcoes);
		}
		int escolha = escolha(0 , opcoesAtualizaContato.length - 1);
		switch (escolha) {
		case(0) :
			leituraAtualizaContatos();
		    break;
		case(1) :
			System.out.print("Digite o novo nome do contato: ");
			c.setNome(teclado.nextLine());
			break;
		case(2) :
			System.out.print("Digite o novo endereco do contato: ");
			c.setEndereco(teclado.nextLine());
			break;
		case(3) :
			c.setDataAniversario(leituraData(NOVA_DATA_CONTATO));
			break;
		case(4) :
			leituraAtualizaFormaDeContato(c);
			break;
		case(5) :
			leituraAdicionaFormaDeContato(c);
			break;
		case(6) :
			leituraRemoveFormaDeContato(c);
			break;
		}
		
	}
	/**
	 * Mostra o perfil atual e opcoes para modificao de dados.
	 */
	private static void leituraAtualizaPerfil(){
		System.out.println();
		System.out.println("Perfil atual:");
		System.out.println("Nome: " + perfil.getNome());
		System.out.println("Email: " + perfil.getEmail());
		System.out.println("Descricao: " + perfil.getDescricao());
		System.out.println();
		
		for (String opcao : opcoesAtualizaPerfil){
			System.out.println(opcao);
		}
		int escolha = escolha(0,opcoesAtualizaPerfil.length - 1 );
		switch (escolha) {
		case(1):
			System.out.print("Digite o novo nome: ");
			perfil.setNome(teclado.nextLine());
			break;
		case(2):
			System.out.print("Digite o novo email: ");
			perfil.setEmail(teclado.nextLine());
			break;
		case(3):
			System.out.print("Digite a nova descricao: ");
			perfil.setDescricao(teclado.nextLine());
			break;
		}
	}
	/**
	 * Oferece uma lista de forma de contatos, da qual o usuario escolhe qual sera removido.
	 * @param contato Contato do qual a lista de formas de contato � retirada para mostra
	 */
	private static void leituraRemoveFormaDeContato(Contato contato) {
		System.out.println("\nFormas de Contato de " + contato.getNome() + "\n");
		int i = 1;
		for(FormaDeContato formaDeContato : contato.getFormasDeContato()){
			System.out.println(i++ +  " - " + formaDeContato);
		}
		System.out.println("0 - Voltar");
		int escolha = escolha(0, contato.getFormasDeContato().size());
		if (escolha == 0)
			return;
		
		contato.removeFormaDeContato(contato.getFormasDeContato().get(escolha-1));
		System.out.println("Forma de contato removida!");
	}
	/**
	 * Chama o metodo para adicao de nova forma de contato e oferece a opcao de adicionar outras formas de contato.
	 * @param contato Contato que recebera uma nova forma de contato
	 */
	private static void leituraAdicionaFormaDeContato(Contato contato) {
		String msg = "Deseja adicionar outra forma de contato? (sim,s/nao,n)";
		do {
			contato.addFormaDeContato(leituraFormaDeContato());
		} while (leituraSimNao(msg));
	}
	/**
	 * Oferece uma lista de formas de contato a partir do Contato, onde o Usuario escolhe qual sera atualizado.
	 * @param contato Contato do qual a lista de formas de contato � retirada para mostra
	 */
	private static void leituraAtualizaFormaDeContato(Contato contato) {
		System.out.println("\nFormas de Contato de " + contato.getNome() + "\n");
		int i = 1;
		for(FormaDeContato formaDeContato : contato.getFormasDeContato()){
			System.out.println(i++ +  " - " + formaDeContato);
		}
		System.out.println("0 - Voltar");
		int escolha = escolha(0, contato.getFormasDeContato().size());
		if (escolha == 0) {
			leituraAtualizaContatos(contato);
			return;
		}
		leituraAtualizaFormaDeContato(contato.getFormasDeContato().get(escolha-1), contato );
	}
	/**
	 * Oferece lista com opcoes de dados da forma de contato a ser atualizado. 
	 * @param f Forma de contato sendo atualizada
	 * @param contato Contato que contem a forma de contato
	 */
	private static void leituraAtualizaFormaDeContato(FormaDeContato f,Contato contato){
		if (!(f instanceof FormaDeContato)) return;
		System.out.println("\nAlterando a Forma de Contato: " + f + " de " + contato.getNome()+ "\n");
		for (String opcoes : opcoesAtualizaFormaDeContato){
			System.out.println(opcoes);
		}
		int escolha = escolha(0,opcoesAtualizaFormaDeContato.length - 1);
		switch (escolha) {
		case(0) :
			leituraAtualizaFormaDeContato(contato);
			break;
		case(1) :
			System.out.print("Digite o novo tipo: ");
			f.setTipo(teclado.nextLine());
			break;
		case(2) :
			System.out.print("Digite o novo endereco: ");
			f.setEndereco(teclado.nextLine());
			break;
		case(3) :
			System.out.print("Digite o novo comentario: ");
			f.setComentario(teclado.nextLine());
			break;
		} 		
	}
	/**
	 * Oferece uma lista de evento, da qual o usuario escolhe qual sera removido.
	 * @return Evento escolhido pelo usuario
	 */

	// Metodos Auxiliares         ----------------------------------------------------------------
	
	/**
	 * Oferece uma lista de eventos, da qual o usuario escolhera um evento
	 * @return Evento escolhido pelo usuario
	 */
	private static Evento leituraBuscaEvento() {
		int i = 1;
		
		System.out.println("\n\nLista de eventos:");
		for(Evento evento : gerente.getEventos()){
			System.out.println(i++ + " - " + evento.getNome() + ", "+ evento.getHorario());
		}
		System.out.println("\nDigite o numero correspondente ao evento ou 0 para voltar");
		int escolha = escolha(0, gerente.getContatos().size());
		if (escolha == 0) return null;
		return gerente.getEventos().get(escolha-1);
	}
	/**
	 * Recebe os dados do usuario para cadastro de uma nova forma de contato. 
	 * @return
	 */
	private static FormaDeContato leituraFormaDeContato() {
		String tipo,informacao,comentario;
		System.out.print("Qual o tipo da forma de contato: ");
		tipo = teclado.nextLine();
		
		System.out.print("Qual a informacao referente a esse tipo: ");
		informacao = teclado.nextLine();
		
		String msg = "Deseja adicionar algum comentario a esta forma de contato: (sim,s/nao,n)";
		
		if(leituraSimNao(msg)){
			System.out.print("Qual comentario: ");
			comentario = teclado.nextLine();
		} else {
			comentario = "Sem Comentario";
		}
		FormaDeContato f = new FormaDeContato(tipo, informacao , comentario);
		return f;
	}
	/**
	 * Faz a leitura da duracao de um evento obedecendo regras de formatacao.
	 * @return Duracao do evento
	 */
	private static int leituraDuracao(){
		int duracao;;
		do {
			try {
				System.out.print("Quantos minutos o evento vai durar: ");
				duracao = Integer.parseInt(teclado.nextLine());
				break;
			} catch (Exception e) {
				System.out.println(FORMATO_INVALIDO);
			}
		} while (true);
		return duracao;
	}
	/**
	 * A partir de uma parte do nome, a qual o usuario digitara, busca um contato que comece com esta parte.
	 * @return Contato escolhido pelo usuario
	 */
	private static Contato leituraBuscaContatoPorNome() {
		String nome;
		int escolha;
		
		System.out.print("Digite uma parte do nome do contato: ");
		nome = teclado.nextLine();
		
		String msg = "Deseja buscar por outro contato: (sim,s/nao,n)";
		do {
			int i = 1;
			try{
				if (gerente.buscaContatoPorNome(nome).size() == 0) {
					System.out.println("Nenhum contato foi encontrado com este nome");
					
					if (leituraSimNao(msg)){
						System.out.print("Digite uma parte do nome do contato: ");
						nome = teclado.nextLine();
						continue;
					}
					return null;
				}
				for (Contato contato : gerente.buscaContatoPorNome(nome)){
					System.out.println( i++ + " - " + contato.getNome());
				}
				System.out.print("Qual contato deseja selecionar, digite o numero correspondente ou '0' para buscar por outro nome: ");
				escolha = Integer.parseInt(teclado.nextLine());
				if (escolha < 0 || escolha > gerente.buscaContatoPorNome(nome).size()) throw new Exception();
				if (escolha == 0){
					System.out.print("Digite uma parte do nome do contato: ");
					nome = teclado.nextLine();
					continue;
				}
				break;
			} catch (Exception e){
				System.out.println("\n" + FORMATO_INVALIDO + "\n");
			}
		} while (true);
			
		return gerente.buscaContatoPorNome(nome).get(escolha-1);
	}
	/**
	 * Faz a leitura do horario de um evento obedecendo regras de formatacao.
	 * @param data Data do evento
	 * @return Horario do evento
	 */
	private static Horario leituraHorario(String data) {
		Horario horario;
		String hora = "";
		String [] dataList = data.split("/"), horaList;
		do{
			System.out.print("Em que horario o evento iniciara (hora:minuto): ");
			try {
				hora = teclado.nextLine();
				horaList = hora.split(":");
				if (horaList.length != 2) throw new Exception();
				horario = new Horario(
						Integer.parseInt(dataList[2]),
						Mes.values()[Integer.parseInt(dataList[1])-1],
						Integer.parseInt(dataList[0]),
						Integer.parseInt(horaList[0]),
						Integer.parseInt(horaList[1])
						);
				break;
			} catch (Exception e) {
				System.out.println(FORMATO_INVALIDO);
			}
		} while (true);
		return horario;
	
	}
	/**
	 * Faz a leitura da data de um evento obedecendo regras de formatacao.
	 * @param prompt Pergunta mostrada ao usuario especificando a data requerida.
	 * @return
	 */
	private static String leituraData(String prompt){
		String data = "";
		do{
			System.out.print(prompt);
			try {
				data = teclado.nextLine();
				String[] dataList = data.split("/");
				if (dataList.length != 3) throw new Exception();
				new Horario(
						Integer.parseInt(dataList[2]),
						Mes.values()[Integer.parseInt(dataList[1])-1],
						Integer.parseInt(dataList[0]),
						1,1);
				break;
			} catch (Exception e) {
				System.out.println(FORMATO_INVALIDO);
			}	
		} while (true);
		return data;
	}
}

